home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / SLAX 6.0.8 / slax-6.0.8.iso / slax / base / 006-devel.lzm / usr / include / kjs / lookup.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-01-15  |  15.5 KB  |  402 lines

  1. // -*- c-basic-offset: 2 -*-
  2. /*
  3.  *  This file is part of the KDE libraries
  4.  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
  5.  *  Copyright (C) 2003 Apple Computer, Inc.
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Lesser General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Lesser General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU Lesser General Public
  18.  *  License along with this library; if not, write to the Free Software
  19.  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  20.  *
  21.  */
  22.  
  23. #ifndef _KJSLOOKUP_H_
  24. #define _KJSLOOKUP_H_
  25.  
  26. #include "identifier.h"
  27. #include "value.h"
  28. #include "object.h"
  29. #include "interpreter.h"
  30. #include <stdio.h>
  31.  
  32. namespace KJS {
  33.  
  34.   /**
  35.    * An entry in a hash table.
  36.    */
  37.   struct HashEntry {
  38.     /**
  39.      * s is the offset to the string key (e.g. a property name)
  40.      */
  41.     unsigned short soffset;
  42.     /**
  43.      * value is the result value (usually an enum value)
  44.      */
  45.     short int value;
  46.     /**
  47.      * attr is a set for flags (e.g. the property flags, see object.h)
  48.      */
  49.     unsigned char attr;
  50.     /**
  51.      * params is another number. For property hashtables, it is used to
  52.      * denote the number of argument of the function
  53.      */
  54.     unsigned char params;
  55.     /**
  56.      * next is the index to the next entry for the same hash value
  57.      */
  58.     short next;
  59.   };
  60.  
  61.   /**
  62.    * A hash table
  63.    * Usually the hashtable is generated by the create_hash_table script, from a .table file.
  64.    *
  65.    * The implementation uses an array of entries, "size" is the total size of that array.
  66.    * The entries between 0 and hashSize-1 are the entry points
  67.    * for each hash value, and the entries between hashSize and size-1
  68.    * are the overflow entries for the hash values that need one.
  69.    * The "next" pointer of the entry links entry points to overflow entries,
  70.    * and links overflow entries between them.
  71.    */
  72.   struct HashTable {
  73.     /**
  74.      * type is a version number. Currently always 2
  75.      */
  76.     int type;
  77.     /**
  78.      * size is the total number of entries in the hashtable, including the null entries,
  79.      * i.e. the size of the "entries" array.
  80.      * Used to iterate over all entries in the table
  81.      */
  82.     int size;
  83.     /**
  84.      * pointer to the array of entries
  85.      * Mind that some entries in the array are null (0,0,0,0).
  86.      */
  87.     const HashEntry *const entries;
  88.     /**
  89.      * the maximum value for the hash. Always smaller than size.
  90.      */
  91.     int hashSize;
  92.  
  93.     /**
  94.      * pointer to the string table.
  95.      */
  96.     const char* const sbase;
  97.   };
  98.  
  99.   /**
  100.    * @short Fast keyword lookup.
  101.    */
  102.   class KJS_EXPORT Lookup {
  103.   public:
  104.     /**
  105.      * Find an entry in the table, and return its value (i.e. the value field of HashEntry)
  106.      */
  107.     static int find(const struct HashTable *table, const Identifier &s);
  108.     static int find(const struct HashTable *table,
  109.             const UChar *c, unsigned int len);
  110.  
  111.     /**
  112.      * Find an entry in the table, and return the entry
  113.      * This variant gives access to the other attributes of the entry,
  114.      * especially the attr field.
  115.      */
  116.     static const HashEntry* findEntry(const struct HashTable *table,
  117.                                       const Identifier &s);
  118.     static const HashEntry* findEntry(const struct HashTable *table,
  119.                                       const UChar *c, unsigned int len);
  120.  
  121.     /**
  122.      * Calculate the hash value for a given key
  123.      */
  124.     static unsigned int hash(const Identifier &key);
  125.     static unsigned int hash(const UChar *c, unsigned int len);
  126.     static unsigned int hash(const char *s);
  127.   };
  128.  
  129.   class ExecState;
  130.   class UString;
  131.   /**
  132.    * @internal
  133.    * Helper for lookupFunction and lookupValueOrFunction
  134.    */
  135.   template <class FuncImp>
  136.   inline Value lookupOrCreateFunction(ExecState *exec, const Identifier &propertyName,
  137.                                       const ObjectImp *thisObj, int token, int params, int attr)
  138.   {
  139.       // Look for cached value in dynamic map of properties (in ObjectImp)
  140.       ValueImp * cachedVal = thisObj->ObjectImp::getDirect(propertyName);
  141.       /*if (cachedVal)
  142.         fprintf(stderr, "lookupOrCreateFunction: Function -> looked up in ObjectImp, found type=%d\n", cachedVal->type());*/
  143.       if (cachedVal)
  144.         return Value(cachedVal);
  145.  
  146.       ObjectImp* func = new FuncImp( exec, token, params );
  147.       Value val( func );
  148.       func->setFunctionName( propertyName );
  149.       ObjectImp *thatObj = const_cast<ObjectImp *>(thisObj);
  150.       thatObj->ObjectImp::put(exec, propertyName, val, attr);
  151.       return val;
  152.   }
  153.  
  154.   /**
  155.    * Helper method for property lookups
  156.    *
  157.    * This method does it all (looking in the hashtable, checking for function
  158.    * overrides, creating the function or retrieving from cache, calling
  159.    * getValueProperty in case of a non-function property, forwarding to parent if
  160.    * unknown property).
  161.    *
  162.    * Template arguments:
  163.    *   - @c FuncImp the class which implements this object's functions
  164.    *   - @c ThisImp the class of "this". It must implement the 
  165.    *        getValueProperty(exec,token) method, for non-function properties.
  166.    *   - @c ParentImp the class of the parent, to propagate the lookup.
  167.    *
  168.    * Method arguments:
  169.    * @param exec execution state, as usual
  170.    * @param propertyName the property we're looking for
  171.    * @param table the static hashtable for this class
  172.    * @param thisObj "this"
  173.    */
  174.   template <class FuncImp, class ThisImp, class ParentImp>
  175.   inline Value lookupGet(ExecState *exec, const Identifier &propertyName,
  176.                          const HashTable* table, const ThisImp* thisObj)
  177.   {
  178.     const HashEntry* entry = Lookup::findEntry(table, propertyName);
  179.  
  180.     if (!entry) // not found, forward to parent
  181.       return thisObj->ParentImp::get(exec, propertyName);
  182.  
  183.     //fprintf(stderr, "lookupGet: found value=%d attr=%d\n", entry->value, entry->attr);
  184.     if (entry->attr & Function)
  185.       return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
  186.     return thisObj->getValueProperty(exec, entry->value);
  187.   }
  188.  
  189.   /**
  190.    * Simplified version of lookupGet in case there are only functions.
  191.    * Using this instead of lookupGet prevents 'this' from implementing a dummy getValueProperty.
  192.    */
  193.   template <class FuncImp, class ParentImp>
  194.   inline Value lookupGetFunction(ExecState *exec, const Identifier &propertyName,
  195.                          const HashTable* table, const ObjectImp* thisObj)
  196.   {
  197.     const HashEntry* entry = Lookup::findEntry(table, propertyName);
  198.  
  199.     if (!entry) // not found, forward to parent
  200.       return static_cast<const ParentImp *>(thisObj)->ParentImp::get(exec, propertyName);
  201.  
  202.     if (entry->attr & Function)
  203.       return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
  204.  
  205.     fprintf(stderr, "Function bit not set! Shouldn't happen in lookupGetFunction!\n" );
  206.     return Undefined();
  207.   }
  208.  
  209.   /**
  210.    * Simplified version of lookupGet in case there are no functions, only "values".
  211.    * Using this instead of lookupGet removes the need for a FuncImp class.
  212.    */
  213.   template <class ThisImp, class ParentImp>
  214.   inline Value lookupGetValue(ExecState *exec, const Identifier &propertyName,
  215.                            const HashTable* table, const ThisImp* thisObj)
  216.   {
  217.     const HashEntry* entry = Lookup::findEntry(table, propertyName);
  218.  
  219.     if (!entry) // not found, forward to parent
  220.       return thisObj->ParentImp::get(exec, propertyName);
  221.  
  222.     if (entry->attr & Function)
  223.       fprintf(stderr, "Function bit set! Shouldn't happen in lookupGetValue! propertyName was %s\n", propertyName.ascii() );
  224.     return thisObj->getValueProperty(exec, entry->value);
  225.   }
  226.  
  227.   /**
  228.    * This one is for "put".
  229.    * Lookup hash entry for property to be set, and set the value.
  230.    */
  231.   template <class ThisImp, class ParentImp>
  232.   inline void lookupPut(ExecState *exec, const Identifier &propertyName,
  233.                         const Value& value, int attr,
  234.                         const HashTable* table, ThisImp* thisObj)
  235.   {
  236.     const HashEntry* entry = Lookup::findEntry(table, propertyName);
  237.  
  238.     if (!entry) // not found: forward to parent
  239.       thisObj->ParentImp::put(exec, propertyName, value, attr);
  240.     else if (entry->attr & Function) // function: put as override property
  241.       thisObj->ObjectImp::put(exec, propertyName, value, attr);
  242.     else if (entry->attr & ReadOnly) // readonly! Can't put!
  243. #ifdef KJS_VERBOSE
  244.       fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
  245. #else
  246.       ; // do nothing
  247. #endif
  248.     else
  249.       thisObj->putValueProperty(exec, entry->value, value, attr);
  250.   }
  251.  
  252.  
  253.   /**
  254.    * This template method retrieves or create an object that is unique
  255.    * (for a given interpreter) The first time this is called (for a given
  256.    * property name), the Object will be constructed, and set as a property
  257.    * of the interpreter's global object. Later calls will simply retrieve
  258.    * that cached object. Note that the object constructor must take 1 argument, exec.
  259.    */
  260.   template <class ClassCtor>
  261.   inline KJS::Object cacheGlobalObject(ExecState *exec, const Identifier &propertyName)
  262.   {
  263.     ValueImp *obj = static_cast<KJS::ObjectImp*>(exec->interpreter()->globalObject().imp())->getDirect(propertyName);
  264.     if (obj)
  265.       return KJS::Object::dynamicCast(Value(obj));
  266.     else
  267.     {
  268.       KJS::Object newObject(new ClassCtor(exec));
  269.       exec->interpreter()->globalObject().put(exec, propertyName, newObject, Internal);
  270.       return newObject;
  271.     }
  272.   }
  273.  
  274.  
  275.   /**
  276.    * Helpers to define prototype objects (each of which simply implements
  277.    * the functions for a type of objects).
  278.    * Sorry for this not being very readable, but it actually saves much copy-n-paste.
  279.    * ParentProto is not our base class, it's the object we use as fallback.
  280.    * The reason for this is that there should only be ONE DOMNode.hasAttributes (e.g.),
  281.    * not one in each derived class. So we link the (unique) prototypes between them.
  282.    *
  283.    * Using those macros is very simple: define the hashtable (e.g. "DOMNodeProtoTable"), then
  284.    * DEFINE_PROTOTYPE("DOMNode",DOMNodeProto)
  285.    * IMPLEMENT_PROTOFUNC(DOMNodeProtoFunc)
  286.    * IMPLEMENT_PROTOTYPE(DOMNodeProto,DOMNodeProtoFunc)
  287.    * and use DOMNodeProto::self(exec) as prototype in the DOMNode constructor.
  288.    * If the prototype has a "parent prototype", e.g. DOMElementProto falls back on DOMNodeProto,
  289.    * then the last line will use IMPLEMENT_PROTOTYPE_WITH_PARENT, with DOMNodeProto as last argument.
  290.    * PUBLIC_DEFINE_PROTOTYPE and PUBLIC_IMPLEMENT_PROTOTYPE are versions with support for separate compilation
  291.    */
  292.  
  293. #define PUBLIC_DEFINE_PROTOTYPE(ClassName,ClassProto) \
  294.   namespace KJS { \
  295.   class ClassProto : public KJS::ObjectImp { \
  296.     friend KJS::Object cacheGlobalObject<ClassProto>(KJS::ExecState *exec, const KJS::Identifier &propertyName); \
  297.   public: \
  298.     static KJS::Object self(KJS::ExecState *exec) \
  299.     { \
  300.       return cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
  301.     } \
  302.   protected: \
  303.     ClassProto( KJS::ExecState *exec ) \
  304.       : KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \
  305.     \
  306.   public: \
  307.     virtual const KJS::ClassInfo *classInfo() const { return &info; } \
  308.     static const KJS::ClassInfo info; \
  309.     KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
  310.     bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
  311.   }; \
  312.   }
  313.  
  314. #define IMPLEMENT_CLASSINFO(ClassName,ClassProto) \
  315.   namespace KJS {\
  316.   const KJS::ClassInfo ClassProto::info = { ClassName, 0, &ClassProto##Table, 0 }; \
  317.   }
  318.  
  319. #define DEFINE_PROTOTYPE(ClassName,ClassProto) \
  320.   PUBLIC_DEFINE_PROTOTYPE(ClassName,ClassProto) \
  321.   IMPLEMENT_CLASSINFO(ClassName,ClassProto)
  322.  
  323. #define IMPLEMENT_PROTOTYPE(ClassProto,ClassFunc) \
  324.     KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
  325.     { \
  326.       /*fprintf( stderr, "%sProto::get(%s) [in macro, no parent]\n", info.className, propertyName.ascii());*/ \
  327.       return lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
  328.     } \
  329.     bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
  330.     { /*stupid but we need this to have a common macro for the declaration*/ \
  331.       return KJS::ObjectImp::hasProperty(exec, propertyName); \
  332.     }
  333.  
  334. #define PUBLIC_IMPLEMENT_PROTOTYPE(ClassProto,ClassName,ClassFunc) \
  335.     IMPLEMENT_PROTOTYPE(ClassProto,ClassFunc)\
  336.     IMPLEMENT_CLASSINFO(ClassName,ClassProto)
  337.  
  338. #define IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassFunc,ParentProto)  \
  339.     KJS::Value KJS::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
  340.     { \
  341.       /*fprintf( stderr, "%sProto::get(%s) [in macro]\n", info.className, propertyName.ascii());*/ \
  342.       KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \
  343.       if ( val.type() != UndefinedType ) return val; \
  344.       /* Not found -> forward request to "parent" prototype */ \
  345.       return ParentProto::self(exec).get( exec, propertyName ); \
  346.     } \
  347.     bool KJS::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
  348.     { \
  349.       if (KJS::ObjectImp::hasProperty(exec, propertyName)) \
  350.         return true; \
  351.       return ParentProto::self(exec).hasProperty(exec, propertyName); \
  352.     }
  353.     
  354. #define PUBLIC_IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassName,ClassFunc,ParentProto)  \
  355.     IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassProto,ClassFunc,ParentProto) \
  356.     IMPLEMENT_CLASSINFO(ClassName,ClassProto)
  357.  
  358. #define IMPLEMENT_PROTOFUNC(ClassFunc) \
  359.   namespace KJS { \
  360.   class ClassFunc : public ObjectImp { \
  361.   public: \
  362.     ClassFunc(KJS::ExecState *exec, int i, int len) \
  363.        : ObjectImp( /*proto? */ ), id(i) { \
  364.        KJS::Value protect(this); \
  365.        put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum); \
  366.     } \
  367.     virtual bool implementsCall() const { return true; } \
  368.     /** You need to implement that one */ \
  369.     virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \
  370.   private: \
  371.     int id; \
  372.   }; \
  373.   }
  374.  
  375.   // To be used in all call() implementations, before casting the type of thisObj
  376. #define KJS_CHECK_THIS( ClassName, theObj ) \
  377.   if (!theObj.isValid() || !theObj.inherits(&ClassName::info)) { \
  378.     KJS::UString errMsg = "Attempt at calling a function that expects a "; \
  379.     errMsg += ClassName::info.className; \
  380.     errMsg += " on a "; \
  381.     errMsg += thisObj.className(); \
  382.     KJS::Object err = KJS::Error::create(exec, KJS::TypeError, errMsg.ascii()); \
  383.     exec->setException(err); \
  384.     return err; \
  385.   }
  386.  
  387.   /*
  388.    * List of things to do when porting an objectimp to the 'static hashtable' mechanism:
  389.    * - write the hashtable source, between @begin and @end
  390.    * - add a rule to build the .lut.h
  391.    * - include the .lut.h
  392.    * - mention the table in the classinfo (add a classinfo if necessary)
  393.    * - write/update the class enum (for the tokens)
  394.    * - turn get() into getValueProperty(), put() into putValueProperty(), using a switch and removing funcs
  395.    * - write get() and/or put() using a template method
  396.    * - cleanup old stuff (e.g. hasProperty)
  397.    * - compile, test, commit ;)
  398.    */
  399. } // namespace
  400.  
  401. #endif
  402.